package com.itlong.cloud.operate.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.itlong.cloud.POJO.DTO.operate.OperateBusinessChargeDTO;
import com.itlong.cloud.POJO.PO.*;
import com.itlong.cloud.POJO.VO.operate.*;
import com.itlong.cloud.PlatformConstants;
import com.itlong.cloud.commons.dao.IPaymentTradeDao;
import com.itlong.cloud.constants.RabbitMQConstant;
import com.itlong.cloud.constants.RedisConstant;
import com.itlong.cloud.enumerate.DataStatusEnum;
import com.itlong.cloud.enumerate.SmartCommunityEnum;
import com.itlong.cloud.operate.dao.IOperateBusinessChargeDao;
import com.itlong.cloud.operate.service.IOperateBusinessChargeService;
import com.itlong.cloud.rabbitmq.config.MessageSender;
import com.itlong.cloud.service.RedisService;
import com.itlong.cloud.utils.data.handler.SqlUtil;
import com.itlong.cloud.utils.date.DateUtil;
import com.itlong.cloud.utils.node.JsonUtil;
import com.itlong.cloud.utils.page.Page;
import com.itlong.cloud.utils.random.LogicIdUtil;
import com.itlong.cloud.utils.words.StringHandlerUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * <desc>
 *      运营-商务收费管理服务层接口实现类
 * </desc>
 *
 * @createDate 2019/08/06
 */
@Service
public class OperateBusinessChargeServiceImpl implements IOperateBusinessChargeService {

    private static final Logger LOG = LoggerFactory.getLogger(OperateBusinessChargeServiceImpl.class);

    @Autowired
    private IOperateBusinessChargeDao iOperateBusinessChargeDao;

    @Autowired
    private MessageSender messageSender;

    @Autowired
    RedisService redisService;

    @Autowired
    private IPaymentTradeDao iWechatPayDao;

    private static final String FORM_FORMAT = "SE";

    /**
     * <desc>
     *      分页获取商务收费信息
     * </desc>
     *
     * @param operateBusinessChargeDTO 商务收费信息DTO
     * @return 商务收费信息
     * @author wangzhi
     * @createDate 2019/08/06
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public Page<OperateBusinessChargeVO> getPage(OperateBusinessChargeDTO operateBusinessChargeDTO) throws Exception {
        if (StringUtils.isBlank(operateBusinessChargeDTO.getOrderColumn())) {
            operateBusinessChargeDTO.setOrderColumn("createTime");
            operateBusinessChargeDTO.setOrderRule("DESC");
        }
        Map<String, Object> params = SqlUtil.convertBeanToMapParams(operateBusinessChargeDTO);
        if (StringUtils.isNotBlank(operateBusinessChargeDTO.getFeeStatus())){
            params.put("feeStatus", StringHandlerUtil.splitStringList(operateBusinessChargeDTO.getFeeStatus()));
        }
        if (StringUtils.isNotBlank(operateBusinessChargeDTO.getEndStatus()) && operateBusinessChargeDTO.getEndStatus().contains(",")){
            params.put("endStatus", null);
        }
        Page<OperateBusinessChargeVO> page = new Page<>();
        page.getPage().setPageSize(operateBusinessChargeDTO.getPageSize());
        page.getPage().setCurrentPage(operateBusinessChargeDTO.getCurrentPage());
        params.put("startSlip", page.getPage().getStartSlip());
        params.put("pageSize", page.getPage().getPageSize());
        List<OperateBusinessChargeVO> operateBusinessChargeVOList = iOperateBusinessChargeDao.getPage(params);
        Set<String> batchNumberSet = new HashSet<>();
        for (OperateBusinessChargeVO operateBusinessChargeVO : operateBusinessChargeVOList) {
            batchNumberSet.add(operateBusinessChargeVO.getBatchNumber());
        }
        if (!batchNumberSet.isEmpty()) {
            // 获取对应批次号的最后一条账单id
            List<String> lastOrderIdList = iOperateBusinessChargeDao.getLastList(batchNumberSet);
            // 获取被多条复用的old_batch_number连接字符串
            String oldBatchNumberString = iOperateBusinessChargeDao.getOldBatchNumberConcat(batchNumberSet);
            for (OperateBusinessChargeVO operateBusinessChargeVO : operateBusinessChargeVOList) {
                // 包含，则是最后一条账单id，此时还要考虑是否被拿去和别的批次号进行多条复用，被多条复用后，则不能再复用，也就不是该批次号最后一条账单
                if (lastOrderIdList.contains(operateBusinessChargeVO.getOrderId()) &&
                        (StringUtils.isBlank(oldBatchNumberString) || !oldBatchNumberString.contains(operateBusinessChargeVO.getBatchNumber()))) {
                    operateBusinessChargeVO.setTheLastOne(1);
                } else {
                    operateBusinessChargeVO.setTheLastOne(0);
                }
            }
        }
        page.setRows(operateBusinessChargeVOList, iOperateBusinessChargeDao.getRecordCount(params));
        return page;
    }

    /**
     * <desc>
     *      获取商务收费信息详情
     * </desc>
     *
     * @param operateBusinessChargeDTO 商务收费信息DTO
     * @return 商务收费信息详情
     * @author wangzhi
     * @createDate 2019/08/06
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public List<OperateBusinessChargeVO> getOne(OperateBusinessChargeDTO operateBusinessChargeDTO) throws Exception {
        List<String> orderIdList = StringHandlerUtil.splitStringList(operateBusinessChargeDTO.getOrderIds());
        List<OperateBusinessChargeVO> operateBusinessChargeVOList = iOperateBusinessChargeDao.getOne(orderIdList);
        if (operateBusinessChargeDTO.getOperateType() == 1) {
            // 复用时获取上期收费金额，即批次号最后添加的一期
            List<OperateBusinessChargeVO> prePaidAmountList = iOperateBusinessChargeDao.getPrePaidAmount(orderIdList);
            if (prePaidAmountList != null && !prePaidAmountList.isEmpty()) {
                for (OperateBusinessChargeVO operateBusinessChargeVO : operateBusinessChargeVOList) {
                    for (OperateBusinessChargeVO prePaidAmount : prePaidAmountList) {
                        if (prePaidAmount.getOrderId().equals(operateBusinessChargeVO.getOrderId())) {
                            operateBusinessChargeVO.setPrePaidAmount(prePaidAmount.getPrePaidAmount());
                            prePaidAmountList.remove(prePaidAmount);
                            break;
                        }
                    }
                }
            }
        } else {
            // 打印或详情时获取上期收费金额，即选中的那一期的上一期
            for (String orderId : orderIdList) {
                OperateBusinessChargeVO voDetail = iOperateBusinessChargeDao.getPrePaidAmountForDetail(orderId);
                for (OperateBusinessChargeVO operateBusinessChargeVO : operateBusinessChargeVOList) {
                    if (StringUtils.isBlank(operateBusinessChargeVO.getPropertyName())) {
                        operateBusinessChargeDTO.setProjectId(operateBusinessChargeVO.getProjectId());
                        OperatePropertyInformationGetVO propertyInformation = iOperateBusinessChargeDao.getPropertyInformation(operateBusinessChargeDTO);
                        operateBusinessChargeVO.setPropertyName(propertyInformation != null ? propertyInformation.getPropertyName() : null);
                    }
                    if (operateBusinessChargeVO.getOrderId().equals(orderId)) {
                        operateBusinessChargeVO.setPrePaidAmount(voDetail != null ? voDetail.getPrePaidAmount() : null);
                        break;
                    }
                }
            }
        }
        //2021-3-5号产品新增需求，打印时添加返回表单编号,格式为SE + XXX;
        for (OperateBusinessChargeVO operateBusinessChargeVO : operateBusinessChargeVOList){
            String formNumber = FORM_FORMAT + this.getFormNumber();
            operateBusinessChargeVO.setFormNumber(formNumber);
        }
        return operateBusinessChargeVOList;
    }

    /**
     * <desc>
     *      获取业务日志列表
     * </desc>
     *
     * @return 业务日志列表
     * @author wangzhi
     * @createDate 2019/11/26
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public Page<OperateBusinessOperationLogVO> getLogPage(OperateBusinessChargeDTO operateBusinessChargeDTO) throws Exception {
        if (StringUtils.isBlank(operateBusinessChargeDTO.getOrderColumn())) {
            operateBusinessChargeDTO.setOrderColumn("createTime");
            operateBusinessChargeDTO.setOrderRule("DESC");
        }
        List<String> orderIdList = StringHandlerUtil.splitStringList(operateBusinessChargeDTO.getOrderIds());
        Map<String, Object> params = SqlUtil.convertBeanToMapParams(operateBusinessChargeDTO);
        Page<OperateBusinessOperationLogVO> page = new Page<>();
        page.getPage().setPageSize(operateBusinessChargeDTO.getPageSize());
        page.getPage().setCurrentPage(operateBusinessChargeDTO.getCurrentPage());
        params.put("startSlip", page.getPage().getStartSlip());
        params.put("pageSize", page.getPage().getPageSize());
        params.put("orderIdList", orderIdList);
        List<OperateBusinessOperationLogVO> operateBusinessOperationLogVOList = iOperateBusinessChargeDao.getLogPage(params);
        page.setRows(operateBusinessOperationLogVOList, iOperateBusinessChargeDao.getLogRecordCount(params));
        return page;
    }

    /**
     * <desc>
     *      获取设备详情列表
     * </desc>
     *
     * @return 设备详情列表
     * @author wangzhi
     * @createDate 2019/11/26
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public Page<OperateBusinessDeviceVO> getDevicePage(OperateBusinessChargeDTO operateBusinessChargeDTO) throws Exception {
        List<String> batchNumberList = StringHandlerUtil.splitStringList(operateBusinessChargeDTO.getBatchNumber());
        Map<String, Object> params = SqlUtil.convertBeanToMapParams(operateBusinessChargeDTO);
        if (StringUtils.isNotBlank(operateBusinessChargeDTO.getDeviceType())){
            params.put("deviceType", StringHandlerUtil.splitStringList(operateBusinessChargeDTO.getDeviceType()));
        }
        Page<OperateBusinessDeviceVO> page = new Page<>();
        page.getPage().setPageSize(operateBusinessChargeDTO.getPageSize());
        page.getPage().setCurrentPage(operateBusinessChargeDTO.getCurrentPage());
        params.put("startSlip", page.getPage().getStartSlip());
        params.put("pageSize", page.getPage().getPageSize());
        params.put("batchNumberList", batchNumberList);
        List<OperateBusinessDeviceVO> operateBusinessDeviceVOList = iOperateBusinessChargeDao.getDevicePage(params);
        for (OperateBusinessDeviceVO operateBusinessDeviceVO : operateBusinessDeviceVOList) {
            // 电梯
            if (operateBusinessDeviceVO.getEquipType() == 1) {
                operateBusinessDeviceVO.setIsOnline(redisService.get(RedisConstant.DEVICE_ELEVATOR_IS_ONLINE_KEY + operateBusinessDeviceVO.getDeviceUnique()) == null ? 0 : 1);
            }
            // 门禁(包含云门禁和云联动器)
            if (operateBusinessDeviceVO.getEquipType() == 2) {
                operateBusinessDeviceVO.setIsOnline(redisService.get(RedisConstant.DEVICE_ENTRANCE_IS_ONLINE_KEY + operateBusinessDeviceVO.getDeviceUnique()) == null ?
                        (redisService.get(RedisConstant.DEVICE_WIPPEN_IS_ONLINE_KEY + operateBusinessDeviceVO.getDeviceUnique()) == null ? 0 : 1) : 1);
            }
            // 云对讲
            if (operateBusinessDeviceVO.getEquipType() == 3) {
                operateBusinessDeviceVO.setIsOnline(redisService.get(RedisConstant.DEVICE_INTERCOM_IS_ONLINE_KEY + operateBusinessDeviceVO.getDeviceUnique()) == null ? 0 : 1);
            }
            // 平板
            if (operateBusinessDeviceVO.getEquipType() == 4) {
                operateBusinessDeviceVO.setIsOnline(redisService.get(RedisConstant.DEVICE_PAD_IS_ONLINE_KEY + operateBusinessDeviceVO.getDeviceUnique()) == null ? 0 : 1);
            }
        }
        page.setRows(operateBusinessDeviceVOList, iOperateBusinessChargeDao.getDeviceRecordCount(params));
        return page;
    }

    /**
     * <desc>
     *      添加商务收费信息
     * </desc>
     *
     * @param operateBusinessChargeDTO 商务收费信息DTO
     * @return 0失败 1成功 99项目已存在
     * @author wangzhi
     * @createDate 2019/08/07
     */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public Integer save(OperateBusinessChargeDTO operateBusinessChargeDTO) throws Exception {
        if (StringUtils.isNotBlank(operateBusinessChargeDTO.getBatchNumber())) {
            // 校验一个批次号只能有一条未缴账单
            List<String> batchNumberList = StringHandlerUtil.splitStringList(operateBusinessChargeDTO.getBatchNumber());
            PropertyCloudServiceCostOrderInfoPO one = iOperateBusinessChargeDao.getNoPayCost(batchNumberList);
            if (one != null) {
                return -1;
            }
        }
        Date nowTime = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat(DateUtil.DATE_FORMAT_TYPE1);
        SimpleDateFormat sdfDay = new SimpleDateFormat("yyyyMMdd");
        String nowDay = sdfDay.format(nowTime);

        // 构造云服务费账单信息数据
        PropertyCloudServiceCostOrderInfoPO propertyCloudServiceCostOrderInfoPO = new PropertyCloudServiceCostOrderInfoPO();
        propertyCloudServiceCostOrderInfoPO.setOrderId(LogicIdUtil.bussinessId());
        if (StringUtils.isNotBlank(operateBusinessChargeDTO.getBatchNumber()) && !operateBusinessChargeDTO.getBatchNumber().contains(",")) {
            propertyCloudServiceCostOrderInfoPO.setBatchNumber(operateBusinessChargeDTO.getBatchNumber());
        } else {
            // 获取当日最小可用批次号
            String batchNumber = this.getBatchNumber(operateBusinessChargeDTO.getMyUserName(), nowDay);
            // 批次号不能超过999
            if (new Long(batchNumber) > new Long(nowDay + "999")) {
                return -2;
            }
            propertyCloudServiceCostOrderInfoPO.setBatchNumber(batchNumber);
        }
        if (StringUtils.isNotBlank(operateBusinessChargeDTO.getBatchNumber()) && operateBusinessChargeDTO.getBatchNumber().contains(",")) {
            propertyCloudServiceCostOrderInfoPO.setOldBatchNumber(operateBusinessChargeDTO.getBatchNumber());
        }
        propertyCloudServiceCostOrderInfoPO.setBusinessAuditStatus(1);
        propertyCloudServiceCostOrderInfoPO.setProjectId(operateBusinessChargeDTO.getProjectId());
        propertyCloudServiceCostOrderInfoPO.setPaidAmount(new BigDecimal(operateBusinessChargeDTO.getPaidAmount()));
        propertyCloudServiceCostOrderInfoPO.setNextAmount(new BigDecimal(operateBusinessChargeDTO.getNextAmount()));
        Calendar cal = Calendar.getInstance();
        cal.setTime(sdf.parse(operateBusinessChargeDTO.getEndTime()));
        cal.set(Calendar.HOUR_OF_DAY, 23);
        cal.set(Calendar.MINUTE, 59);
        cal.set(Calendar.SECOND, 59);
        propertyCloudServiceCostOrderInfoPO.setEndTime(cal.getTime());
        // 该批次号如果是第一次添加，则赠送，查询该批次号下的一条账单
        PropertyCloudServiceCostOrderInfoPO one = iOperateBusinessChargeDao.getCloudCostByBatchNumber(propertyCloudServiceCostOrderInfoPO.getBatchNumber());
        if (one == null && StringUtils.isBlank(propertyCloudServiceCostOrderInfoPO.getOldBatchNumber())) {
            propertyCloudServiceCostOrderInfoPO.setFeeStatus(2);
            propertyCloudServiceCostOrderInfoPO.setPresented(1);
            propertyCloudServiceCostOrderInfoPO.setAcceptStatus(3);
        } else {
            propertyCloudServiceCostOrderInfoPO.setFeeStatus(1);
            propertyCloudServiceCostOrderInfoPO.setPresented(0);
        }
        propertyCloudServiceCostOrderInfoPO.setBusinessRemark(operateBusinessChargeDTO.getBusinessRemark());
        propertyCloudServiceCostOrderInfoPO.setStatus(DataStatusEnum.NORMAL.getType());
        propertyCloudServiceCostOrderInfoPO.setCreateTime(nowTime);
        propertyCloudServiceCostOrderInfoPO.setUpdateTime(nowTime);
        propertyCloudServiceCostOrderInfoPO.setUploadInfoPrivateName(operateBusinessChargeDTO.getUploadInfoPrivateName());
        propertyCloudServiceCostOrderInfoPO.setUploadInfoPrivateUrl(operateBusinessChargeDTO.getUploadInfoPrivateUrl());
        propertyCloudServiceCostOrderInfoPO.setUploadInfoPublicName(operateBusinessChargeDTO.getUploadInfoPublicName());
        propertyCloudServiceCostOrderInfoPO.setUploadInfoPublicUrl(operateBusinessChargeDTO.getUploadInfoPublicUrl());

        Integer count = iOperateBusinessChargeDao.save(SqlUtil.durableData(propertyCloudServiceCostOrderInfoPO, PlatformConstants.TABLE_SAVE));

        // 构造云服务费收费明细数据
        List<PropertyCloudServiceCostOrderDataPO> propertyCloudServiceCostOrderDataPOList = JSON.parseArray(operateBusinessChargeDTO.getChargeDetail(), PropertyCloudServiceCostOrderDataPO.class);
        for (PropertyCloudServiceCostOrderDataPO propertyCloudServiceCostOrderDataPO : propertyCloudServiceCostOrderDataPOList) {
            propertyCloudServiceCostOrderDataPO.setDataId(LogicIdUtil.bussinessId());
            propertyCloudServiceCostOrderDataPO.setOrderId(propertyCloudServiceCostOrderInfoPO.getOrderId());
            propertyCloudServiceCostOrderDataPO.setProjectId(operateBusinessChargeDTO.getProjectId());

            cal.setTime(propertyCloudServiceCostOrderDataPO.getStartTime());
            cal.set(Calendar.HOUR_OF_DAY, 0);
            cal.set(Calendar.MINUTE, 0);
            cal.set(Calendar.SECOND, 0);
            propertyCloudServiceCostOrderDataPO.setStartTime(cal.getTime());
            cal.setTime(propertyCloudServiceCostOrderDataPO.getEndTime());
            cal.set(Calendar.HOUR_OF_DAY, 23);
            cal.set(Calendar.MINUTE, 59);
            cal.set(Calendar.SECOND, 59);
            propertyCloudServiceCostOrderDataPO.setEndTime(cal.getTime());
            propertyCloudServiceCostOrderDataPO.setCreateUserId(operateBusinessChargeDTO.getMyUserName());
            propertyCloudServiceCostOrderDataPO.setOperateUserId(operateBusinessChargeDTO.getMyUserName());
            propertyCloudServiceCostOrderDataPO.setStatus(DataStatusEnum.NORMAL.getType());
            propertyCloudServiceCostOrderDataPO.setCreateTime(nowTime);
            propertyCloudServiceCostOrderDataPO.setUpdateTime(nowTime);
        }
        iOperateBusinessChargeDao.batchSaveOrderData(propertyCloudServiceCostOrderDataPOList);

        // 构造云服务费任务书信息数据
        List<PropertyCloudServiceAssignmentDataPO> propertyCloudServiceAssignmentDataPOList = JSON.parseArray(operateBusinessChargeDTO.getAssignmentDetail(), PropertyCloudServiceAssignmentDataPO.class);
        for (PropertyCloudServiceAssignmentDataPO propertyCloudServiceAssignmentDataPO : propertyCloudServiceAssignmentDataPOList) {
            propertyCloudServiceAssignmentDataPO.setAssignmentId(LogicIdUtil.bussinessId());
            propertyCloudServiceAssignmentDataPO.setSalesmen(propertyCloudServiceAssignmentDataPO.getSaleName());
            propertyCloudServiceAssignmentDataPO.setDepartment(propertyCloudServiceAssignmentDataPO.getDepartmentName());
            propertyCloudServiceAssignmentDataPO.setOrderId(propertyCloudServiceCostOrderInfoPO.getOrderId());
            propertyCloudServiceAssignmentDataPO.setProjectId(operateBusinessChargeDTO.getProjectId());
            propertyCloudServiceAssignmentDataPO.setCreateUserId(operateBusinessChargeDTO.getMyUserName());
            propertyCloudServiceAssignmentDataPO.setOperateUserId(operateBusinessChargeDTO.getMyUserName());
            propertyCloudServiceAssignmentDataPO.setStatus(DataStatusEnum.NORMAL.getType());
            propertyCloudServiceAssignmentDataPO.setCreateTime(nowTime);
            propertyCloudServiceAssignmentDataPO.setUpdateTime(nowTime);
        }
        iOperateBusinessChargeDao.batchSaveAssignmentData(propertyCloudServiceAssignmentDataPOList);

        //修改设备批次号
        List<DeviceBatchNumberDTO> batchNumberVOList = JSON.parseArray(operateBusinessChargeDTO.getDeviceDetail(), DeviceBatchNumberDTO.class);
        if (batchNumberVOList != null && !batchNumberVOList.isEmpty()){
            for (DeviceBatchNumberDTO deviceBatchNumberDTO : batchNumberVOList){
                deviceBatchNumberDTO.setUpdateTime(nowTime);
                deviceBatchNumberDTO.setMyUserName(operateBusinessChargeDTO.getMyUserName());
                deviceBatchNumberDTO.setDeviceType(StringHandlerUtil.getDeviceTypeByDeviceUnique(deviceBatchNumberDTO.getDeviceUnique()));
            }
            iOperateBusinessChargeDao.batchUpdateDeviceBatchNumber(batchNumberVOList);
        }
        // 保存特殊操作日志
        OperateUserInfoPO operateUserInfoPO = iOperateBusinessChargeDao.getOperateUserPO(operateBusinessChargeDTO.getMyUserName());
        Map<String, Object> projectIdAndName = iOperateBusinessChargeDao.getProjectIdAndName(operateBusinessChargeDTO.getProjectId());
        OperationSpecialLogPO operationSpecialLogPO = new OperationSpecialLogPO();
        operationSpecialLogPO.setLogId(LogicIdUtil.bussinessId());
        operationSpecialLogPO.setOuterId(propertyCloudServiceCostOrderInfoPO.getOrderId());
        operationSpecialLogPO.setAccount(operateUserInfoPO.getUserName());
        operationSpecialLogPO.setRealName(operateUserInfoPO.getRealName());
        operationSpecialLogPO.setIp(operateBusinessChargeDTO.getIp());
        operationSpecialLogPO.setFunctionType(1);
        operationSpecialLogPO.setOperateFunction(operateBusinessChargeDTO.getOperateFunction());
        // 金额格式化对象
        DecimalFormat decimalFormat = new DecimalFormat("#0.00");
        operationSpecialLogPO.setOperateDec(operateUserInfoPO.getRealName() + " 添加数据，添加的项目为：" + projectIdAndName.get("projectId") + projectIdAndName.get("projectName")
                + "，批次号为：" + propertyCloudServiceCostOrderInfoPO.getBatchNumber() + "，收费结束时间为：" + operateBusinessChargeDTO.getEndTime()
                + "，应收金额为：" + decimalFormat.format(new BigDecimal(operateBusinessChargeDTO.getPaidAmount())) + "元");
        operationSpecialLogPO.setOperateData(JSON.toJSONString(operateBusinessChargeDTO));
        operationSpecialLogPO.setOperateWay(operateBusinessChargeDTO.getOperateWay());
        operationSpecialLogPO.setStatus(DataStatusEnum.NORMAL.getType());
        operationSpecialLogPO.setCreateTime(nowTime);
        operationSpecialLogPO.setUpdateTime(nowTime);
        iOperateBusinessChargeDao.save(SqlUtil.durableData(operationSpecialLogPO, PlatformConstants.TABLE_SAVE));

        return count;
    }

    /**
     * <desc>
     *      获取批次号，规避并发获取同个情况，因为分布式，服务部署多台服务器，只有synchronized关键字达不到效果
     * </desc>
     *
     * @return 批次号
     * @author wangzhi
     * @createDate 2019/12/11
     */
    private synchronized String getBatchNumber(String userId, String nowDay){
        String markId = LogicIdUtil.bussinessId();
        String key = RedisConstant.OPERATE_BUSINESS_CHARGE_BATCH_NUMBER_KEY + nowDay;
        Long time = RedisConstant.OPERATE_BUSINESS_CHARGE_BATCH_NUMBER_TIME;
        // 获取当日最小可用批次号
        String batchNumber = redisService.get(key);
        if (StringUtils.isBlank(batchNumber) || !this.getLongValue(batchNumber, -1L).equals(-1L)) {
            // 拿到正常的之后赶紧先放一个唯一标志的进去，尽可能规避并发情况
            redisService.set(key, time, markId + "_" + userId);
        } else {
            // 缓存中拿到的批次号不为空且转Long失败，则此时有人正在获取批次号，递归
            return getBatchNumber(userId, nowDay);
        }
        if (StringUtils.isBlank(batchNumber)) {
            // 缓存中还没有今天批次号或规避缓存数据丢失情况，从数据库中先获取当日最大批次号
            String batchNumberData = iOperateBusinessChargeDao.getMaxBatchNumberNowDay(nowDay);
            if (StringUtils.isBlank(batchNumberData)) {
                // 数据库中没有，则当天第一次开始
                batchNumber = nowDay + "001";
                String markValue = redisService.get(key);
                // 获取的值与一开始放入的唯一标志相等，则完成此次获取，并设置下次可用的批次号
                if ((markId + "_" + userId).equals(markValue)) {
                    redisService.set(key, time, new Long(batchNumber) + 1 + "");
                    return batchNumber;
                } else {
                    // 失败了之后再重新拿
                    return getBatchNumber(userId, nowDay);
                }
            } else {
                // 数据库中有，则从最大批次号+1开始
                batchNumber = new Long(batchNumberData) + 1 + "";
                String markValue = redisService.get(key);
                // 获取的值与一开始放入的唯一标志相等，则完成此次获取，并设置下次可用的批次号
                if ((markId + "_" + userId).equals(markValue)) {
                    redisService.set(key, time, new Long(batchNumber) + 1 + "");
                    return batchNumber;
                } else {
                    // 失败了之后再重新拿
                    return getBatchNumber(userId, nowDay);
                }
            }
        } else {
            // 缓存中已经有今天的批次号
            String markValue = redisService.get(key);
            // 获取的值与一开始放入的唯一标志相等，则完成此次获取，并设置下次可用的批次号
            if ((markId + "_" + userId).equals(markValue)) {
                redisService.set(key, time, new Long(batchNumber) + 1 + "");
                return batchNumber;
            } else {
                // 失败了之后再重新拿
                return getBatchNumber(userId, nowDay);
            }
        }
    }

    /**
     * <desc>
     *      String转Long，异常返回默认值
     * </desc>
     *
     * @return 批次号
     * @author wangzhi
     * @createDate 2019/12/11
     */
    private Long getLongValue(String str, Long defaultValue) {
        try {
            return new Long(str);
        } catch (Exception e) {
            return defaultValue;
        }
    }

    /**
     * <desc>
     *      修改商务收费信息
     * </desc>
     *
     * @param operateBusinessChargeDTO 商务收费信息DTO
     * @return 0失败 1成功
     * @author wangzhi
     * @createDate 2019/08/07
     */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public Integer update(OperateBusinessChargeDTO operateBusinessChargeDTO) throws Exception {
        Date nowTime = new Date();
        List<String> orderIdList = new ArrayList<>();
        orderIdList.add(operateBusinessChargeDTO.getOrderId());
        List<OperateBusinessChargeVO> oldOne = iOperateBusinessChargeDao.getOne(orderIdList);
        // 构造云服务费账单信息数据
        PropertyCloudServiceCostOrderInfoPO propertyCloudServiceCostOrderInfoPO = new PropertyCloudServiceCostOrderInfoPO();
        propertyCloudServiceCostOrderInfoPO.setOrderId(operateBusinessChargeDTO.getOrderId());
        propertyCloudServiceCostOrderInfoPO.setProjectId(operateBusinessChargeDTO.getProjectId());
        propertyCloudServiceCostOrderInfoPO.setPaidAmount(new BigDecimal(operateBusinessChargeDTO.getPaidAmount()));
        propertyCloudServiceCostOrderInfoPO.setNextAmount(new BigDecimal(operateBusinessChargeDTO.getNextAmount()));
        SimpleDateFormat sdf = new SimpleDateFormat(DateUtil.DATE_FORMAT_TYPE1);
        Calendar cal = Calendar.getInstance();
        cal.setTime(sdf.parse(operateBusinessChargeDTO.getEndTime()));
        cal.set(Calendar.HOUR_OF_DAY, 23);
        cal.set(Calendar.MINUTE, 59);
        cal.set(Calendar.SECOND, 59);
        propertyCloudServiceCostOrderInfoPO.setBusinessRemark(operateBusinessChargeDTO.getBusinessRemark());
        propertyCloudServiceCostOrderInfoPO.setEndTime(cal.getTime());
        propertyCloudServiceCostOrderInfoPO.setUpdateTime(nowTime);
        propertyCloudServiceCostOrderInfoPO.setUploadInfoPrivateName(operateBusinessChargeDTO.getUploadInfoPrivateName());
        propertyCloudServiceCostOrderInfoPO.setUploadInfoPrivateUrl(operateBusinessChargeDTO.getUploadInfoPrivateUrl());
        propertyCloudServiceCostOrderInfoPO.setUploadInfoPublicName(operateBusinessChargeDTO.getUploadInfoPublicName());
        propertyCloudServiceCostOrderInfoPO.setUploadInfoPublicUrl(operateBusinessChargeDTO.getUploadInfoPublicUrl());

        Integer count = iOperateBusinessChargeDao.update(SqlUtil.durableData(propertyCloudServiceCostOrderInfoPO, PlatformConstants.TABLE_UPDATE));

        // 构造云服务费收费明细数据
        List<PropertyCloudServiceCostOrderDataPO> propertyCloudServiceCostOrderDataPOList = JSON.parseArray(operateBusinessChargeDTO.getChargeDetail(), PropertyCloudServiceCostOrderDataPO.class);
        for (PropertyCloudServiceCostOrderDataPO propertyCloudServiceCostOrderDataPO : propertyCloudServiceCostOrderDataPOList) {
            propertyCloudServiceCostOrderDataPO.setDataId(LogicIdUtil.bussinessId());
            propertyCloudServiceCostOrderDataPO.setOrderId(propertyCloudServiceCostOrderInfoPO.getOrderId());
            propertyCloudServiceCostOrderDataPO.setProjectId(operateBusinessChargeDTO.getProjectId());

            cal.setTime(propertyCloudServiceCostOrderDataPO.getStartTime());
            cal.set(Calendar.HOUR_OF_DAY, 0);
            cal.set(Calendar.MINUTE, 0);
            cal.set(Calendar.SECOND, 0);
            propertyCloudServiceCostOrderDataPO.setStartTime(cal.getTime());
            cal.setTime(propertyCloudServiceCostOrderDataPO.getEndTime());
            cal.set(Calendar.HOUR_OF_DAY, 23);
            cal.set(Calendar.MINUTE, 59);
            cal.set(Calendar.SECOND, 59);
            propertyCloudServiceCostOrderDataPO.setEndTime(cal.getTime());

            propertyCloudServiceCostOrderDataPO.setCreateUserId(operateBusinessChargeDTO.getMyUserName());
            propertyCloudServiceCostOrderDataPO.setOperateUserId(operateBusinessChargeDTO.getMyUserName());
            propertyCloudServiceCostOrderDataPO.setStatus(DataStatusEnum.NORMAL.getType());
            propertyCloudServiceCostOrderDataPO.setCreateTime(nowTime);
            propertyCloudServiceCostOrderDataPO.setUpdateTime(nowTime);
        }
        iOperateBusinessChargeDao.batchDeleteOrderData(operateBusinessChargeDTO);
        iOperateBusinessChargeDao.batchSaveOrderData(propertyCloudServiceCostOrderDataPOList);

        // 构造云服务费任务书信息数据
        List<PropertyCloudServiceAssignmentDataPO> propertyCloudServiceAssignmentDataPOList = JSON.parseArray(operateBusinessChargeDTO.getAssignmentDetail(), PropertyCloudServiceAssignmentDataPO.class);
        for (PropertyCloudServiceAssignmentDataPO propertyCloudServiceAssignmentDataPO : propertyCloudServiceAssignmentDataPOList) {
            propertyCloudServiceAssignmentDataPO.setDepartment(propertyCloudServiceAssignmentDataPO.getDepartmentName());
            propertyCloudServiceAssignmentDataPO.setSalesmen(propertyCloudServiceAssignmentDataPO.getSaleName());
            propertyCloudServiceAssignmentDataPO.setAssignmentId(LogicIdUtil.bussinessId());
            propertyCloudServiceAssignmentDataPO.setOrderId(propertyCloudServiceCostOrderInfoPO.getOrderId());
            propertyCloudServiceAssignmentDataPO.setProjectId(operateBusinessChargeDTO.getProjectId());
            propertyCloudServiceAssignmentDataPO.setCreateUserId(operateBusinessChargeDTO.getMyUserName());
            propertyCloudServiceAssignmentDataPO.setOperateUserId(operateBusinessChargeDTO.getMyUserName());
            propertyCloudServiceAssignmentDataPO.setStatus(DataStatusEnum.NORMAL.getType());
            propertyCloudServiceAssignmentDataPO.setCreateTime(nowTime);
            propertyCloudServiceAssignmentDataPO.setUpdateTime(nowTime);
        }
        iOperateBusinessChargeDao.batchDeleteAssignmentData(operateBusinessChargeDTO);
        iOperateBusinessChargeDao.batchSaveAssignmentData(propertyCloudServiceAssignmentDataPOList);

        //修改设备批次号
        List<DeviceBatchNumberDTO> batchNumberVOList = JSON.parseArray(operateBusinessChargeDTO.getDeviceDetail(), DeviceBatchNumberDTO.class);
        if (batchNumberVOList != null && !batchNumberVOList.isEmpty()){
            for (DeviceBatchNumberDTO deviceBatchNumberDTO : batchNumberVOList){
                deviceBatchNumberDTO.setUpdateTime(nowTime);
                deviceBatchNumberDTO.setMyUserName(operateBusinessChargeDTO.getMyUserName());
                deviceBatchNumberDTO.setDeviceType(StringHandlerUtil.getDeviceTypeByDeviceUnique(deviceBatchNumberDTO.getDeviceUnique()));
            }
            iOperateBusinessChargeDao.batchUpdateDeviceBatchNumber(batchNumberVOList);
        }

        // 保存特殊操作日志
        OperateUserInfoPO operateUserInfoPO = iOperateBusinessChargeDao.getOperateUserPO(operateBusinessChargeDTO.getMyUserName());
        OperationSpecialLogPO operationSpecialLogPO = new OperationSpecialLogPO();
        operationSpecialLogPO.setLogId(LogicIdUtil.bussinessId());
        operationSpecialLogPO.setOuterId(propertyCloudServiceCostOrderInfoPO.getOrderId());
        operationSpecialLogPO.setAccount(operateUserInfoPO.getUserName());
        operationSpecialLogPO.setRealName(operateUserInfoPO.getRealName());
        operationSpecialLogPO.setIp(operateBusinessChargeDTO.getIp());
        operationSpecialLogPO.setFunctionType(1);
        operationSpecialLogPO.setOperateFunction(operateBusinessChargeDTO.getOperateFunction());
        // 金额格式化对象
        DecimalFormat decimalFormat = new DecimalFormat("#0.00");
        operationSpecialLogPO.setOperateDec(operateUserInfoPO.getRealName() + " 修改数据，修改的项目为：" + oldOne.get(0).getProjectId() + oldOne.get(0).getProjectName()
                + "，批次号为：" + oldOne.get(0).getBatchNumber() + "，收费结束时间为：" + operateBusinessChargeDTO.getEndTime()
                + "，应收金额为：" + decimalFormat.format(new BigDecimal(operateBusinessChargeDTO.getPaidAmount())) + "元");
        operationSpecialLogPO.setOperateData(JSON.toJSONString(operateBusinessChargeDTO));
        operationSpecialLogPO.setOperateWay(operateBusinessChargeDTO.getOperateWay());
        operationSpecialLogPO.setStatus(DataStatusEnum.NORMAL.getType());
        operationSpecialLogPO.setCreateTime(nowTime);
        operationSpecialLogPO.setUpdateTime(nowTime);
        iOperateBusinessChargeDao.save(SqlUtil.durableData(operationSpecialLogPO, PlatformConstants.TABLE_SAVE));

        return count;
    }

    /**
     * <desc>
     *      删除商务收费信息
     * </desc>
     *
     * @param operateBusinessChargeDTO 商务收费信息DTO
     * @return 受影响行数，大于0则成功
     * @author wangzhi
     * @createDate 2019/08/07
     */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public Integer delete(OperateBusinessChargeDTO operateBusinessChargeDTO) throws Exception {
        Date nowTime = new Date();
        Integer count = iOperateBusinessChargeDao.delete(operateBusinessChargeDTO);

        // 删除云服务费收费明细数据
        iOperateBusinessChargeDao.batchDeleteOrderData(operateBusinessChargeDTO);

        // 保存特殊操作日志
        OperateUserInfoPO operateUserInfoPO = iOperateBusinessChargeDao.getOperateUserPO(operateBusinessChargeDTO.getMyUserName());
        OperationSpecialLogPO operationSpecialLogPO = new OperationSpecialLogPO();
        operationSpecialLogPO.setLogId(LogicIdUtil.bussinessId());
        operationSpecialLogPO.setOuterId(operateBusinessChargeDTO.getOrderId());
        operationSpecialLogPO.setAccount(operateUserInfoPO.getUserName());
        operationSpecialLogPO.setRealName(operateUserInfoPO.getRealName());
        operationSpecialLogPO.setIp(operateBusinessChargeDTO.getIp());
        operationSpecialLogPO.setFunctionType(1);
        operationSpecialLogPO.setOperateFunction(operateBusinessChargeDTO.getOperateFunction());
        operationSpecialLogPO.setOperateDec(operateUserInfoPO.getRealName() + " 删除数据");
        operationSpecialLogPO.setOperateWay(operateBusinessChargeDTO.getOperateWay());
        operationSpecialLogPO.setStatus(DataStatusEnum.NORMAL.getType());
        operationSpecialLogPO.setCreateTime(nowTime);
        operationSpecialLogPO.setUpdateTime(nowTime);
        iOperateBusinessChargeDao.save(SqlUtil.durableData(operationSpecialLogPO, PlatformConstants.TABLE_SAVE));

        return count;
    }

    /**
     * <desc>
     *      审核商务收费信息
     * </desc>
     *
     * @return 标准格式化响应结果
     * @author wangzhi
     * @createDate 2019/11/26
     */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public Integer audit(OperateBusinessChargeDTO operateBusinessChargeDTO) throws Exception {
        Date nowTime = new Date();
        List<String> orderIdList = StringHandlerUtil.splitStringList(operateBusinessChargeDTO.getOrderIds());
        Integer businessAuditStatus = operateBusinessChargeDTO.getNowAuditStatus();
        String operateName = "";
        switch (operateBusinessChargeDTO.getNowAuditStatus()) {
            case 1:
                if (operateBusinessChargeDTO.getAuditStatus() == 1) {
                    businessAuditStatus = 2;
                    operateName = "提交";
                } else {
                    return -1;
                }
                break;
            case 2:
                if (operateBusinessChargeDTO.getAuditStatus() == 1) {
                    businessAuditStatus = 3;
                    operateName = "审批";
                } else if (operateBusinessChargeDTO.getAuditStatus() == 2) {
                    businessAuditStatus = 1;
                    operateName = "撤回";
                } else {
                    businessAuditStatus = 1;
                    operateName = "回退";
                }
                break;
            case 3:
                if (operateBusinessChargeDTO.getAuditStatus() == 1) {
                    return -1;
                } else {
                    List<OperateBusinessChargeVO> operateBusinessChargeVOList = iOperateBusinessChargeDao.getOne(orderIdList);
                    for (OperateBusinessChargeVO operateBusinessChargeVO : operateBusinessChargeVOList) {
                        if (operateBusinessChargeVO.getPresented() != 1 && operateBusinessChargeVO.getAcceptStatus() == 3) {
                            return -2;
                        }
                    }
                    operateName = "弃审";
                    businessAuditStatus = 2;
                    //项目云服务费变更后需通知该批次号下的云对讲设备
                    String[] orderIds = operateBusinessChargeDTO.getOrderIds().split(",");
                    for(String orderId : orderIds){
                        List<DeviceBusinessChangeLogPO> changeLogPOS = new ArrayList<>();
                        JSONArray jsonArray = new JSONArray();
                        List<Map<String, String>> deviceList = iWechatPayDao.getDeviceInfoByBatchNumber(orderId);
                        if (deviceList != null && !deviceList.isEmpty()) {
                            List<Map<String, String>> allDeviceList = iWechatPayDao.getCloudTalkInfoByProjectId(deviceList.get(0).get("projectId"));
                            if(allDeviceList != null && !allDeviceList.isEmpty()){
                                for (Map<String, String> map : allDeviceList) {
                                    if(StringUtils.isEmpty(map.get("deviceUnique"))){
                                        continue;
                                    }
                                    JSONObject jsonObject = new JSONObject();
                                    jsonObject.put("deviceUnique", map.get("deviceUnique"));
                                    jsonArray.add(jsonObject);
                                }
                            }
                        }

                        //项目云服务费变更后需通知云对讲
                        if (!jsonArray.isEmpty()) {
                            DeviceBusinessChangeLogPO changeLogPO = new DeviceBusinessChangeLogPO(SmartCommunityEnum.PUSH_DEVICE, jsonArray, deviceList.get(0).get("projectId"));
                            changeLogPOS.add(changeLogPO);
                        }
                        //向设备推送设备云对讲指令
                        if (!changeLogPOS.isEmpty()) {
                            JSONObject dataJs = new JSONObject();
                            dataJs.put("data", changeLogPOS);
                            //云对讲
                            messageSender.send(RabbitMQConstant.RABBITMQ_HANDLE_SMART_COMMUNITY_ORDERS_QUEUE,
                                    JsonUtil.toJSON(dataJs), RabbitMQConstant.RABBITMQ_SMART_COMMUNITY_ORDERS_EXCHANGE,
                                    RabbitMQConstant.RABBITMQ_SMART_COMMUNITY_ORDERS_ROUTING_KEY);
                        }
                    }
                }
                break;
            default:
                break;
        }
        Integer count = iOperateBusinessChargeDao.audit(orderIdList, businessAuditStatus);

        // 保存特殊操作日志
        OperateUserInfoPO operateUserInfoPO = iOperateBusinessChargeDao.getOperateUserPO(operateBusinessChargeDTO.getMyUserName());
        List<OperationSpecialLogPO> operationSpecialLogPOList = new ArrayList<>();
        for (String orderId : orderIdList) {
            OperationSpecialLogPO operationSpecialLogPO = new OperationSpecialLogPO();
            operationSpecialLogPO.setLogId(LogicIdUtil.bussinessId());
            operationSpecialLogPO.setOuterId(orderId);
            operationSpecialLogPO.setAccount(operateUserInfoPO.getUserName());
            operationSpecialLogPO.setRealName(operateUserInfoPO.getRealName());
            operationSpecialLogPO.setIp(operateBusinessChargeDTO.getIp());
            operationSpecialLogPO.setFunctionType(1);
            operationSpecialLogPO.setOperateFunction(operateBusinessChargeDTO.getOperateFunction());
            operationSpecialLogPO.setOperateDec(operateUserInfoPO.getRealName() + " " + operateName +
                    (StringUtils.isNotBlank(operateBusinessChargeDTO.getReason()) ? ("，" + operateName + "原因为" + operateBusinessChargeDTO.getReason()) : ""));
            operationSpecialLogPO.setOperateData(JSON.toJSONString(operateBusinessChargeDTO));
            operationSpecialLogPO.setOperateWay(operateBusinessChargeDTO.getOperateWay());
            operationSpecialLogPO.setStatus(DataStatusEnum.NORMAL.getType());
            operationSpecialLogPO.setCreateTime(nowTime);
            operationSpecialLogPO.setUpdateTime(nowTime);
            operationSpecialLogPOList.add(operationSpecialLogPO);
        }
        // 批量保存
        iOperateBusinessChargeDao.batchSaveOperationLogData(operationSpecialLogPOList);

        return count;
    }

    /**
     * <desc>
     *      查询物业信息
     * </desc>
     *
     * @param operateBusinessChargeDTO 商务收费信息DTO
     * @return 物业信息
     * @author wangzhi
     * @createDate 2019/08/07
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public OperatePropertyInformationGetVO getPropertyInformation(OperateBusinessChargeDTO operateBusinessChargeDTO) throws Exception {
        return iOperateBusinessChargeDao.getPropertyInformation(operateBusinessChargeDTO);
    }

    /**
     * <desc>
     *      获取商务收费信息附加信息
     * </desc>
     *
     * @param operateBusinessChargeDTO 财务续费审批DTO
     * @return 商务收费信息附加信息
     * @author wangzhi
     * @createDate 2019/08/15
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public Map<String, Object> getAppendInfo(OperateBusinessChargeDTO operateBusinessChargeDTO) throws Exception {
        Integer type = operateBusinessChargeDTO.getType();
        Integer businessInput = operateBusinessChargeDTO.getBusinessInput();
        Map<String, Object> params = SqlUtil.convertBeanToMapParams(operateBusinessChargeDTO);
        if (StringUtils.isNotBlank(operateBusinessChargeDTO.getFeeStatus())){
            params.put("feeStatus", StringHandlerUtil.splitStringList(operateBusinessChargeDTO.getFeeStatus()));
        }
        if (StringUtils.isNotBlank(operateBusinessChargeDTO.getEndStatus()) && operateBusinessChargeDTO.getEndStatus().contains(",")){
            params.put("endStatus", null);
        }
        Map<String, Object> data = new HashMap<>();
        params.remove("businessAuditStatus");
        params.put("type", 1);  // 所有
        Integer allCount = iOperateBusinessChargeDao.getRecordCount(params);
        params.put("type", 2);  // 即将过期
        Integer willExpireCount = iOperateBusinessChargeDao.getRecordCount(params);
        params.put("type", 0);  // 已过期
        Integer expireCount = iOperateBusinessChargeDao.getRecordCount(params);

        params.put("type", type);
        params.put("businessInput", 0);    // 未录入
        Integer noEntryCount = iOperateBusinessChargeDao.getRecordCount(params);

        params.put("businessInput", businessInput);
        params.put("businessAuditStatus", 1);    // 未提交
        Integer uncommittedCount = iOperateBusinessChargeDao.getRecordCount(params);
        params.put("businessAuditStatus", 2);    // 未审批
        Integer unApproveCount = iOperateBusinessChargeDao.getRecordCount(params);
        params.put("businessAuditStatus", 3);    // 已审批
        Integer approveCount = iOperateBusinessChargeDao.getRecordCount(params);

        data.put("allCount", allCount);
        data.put("willExpireCount", willExpireCount);
        data.put("expireCount", expireCount);
        data.put("uncommittedCount", uncommittedCount);
        data.put("unApproveCount", unApproveCount);
        data.put("approveCount", approveCount);
        data.put("noEntryCount", noEntryCount);
        return data;
    }

    /**
     * <desc>
     *      获取该批次号已录入数据的最大结束时间
     * </desc>
     *
     * @return 该批次号已录入数据的最大结束时间
     * @author wangzhi
     * @createDate 2019/11/25
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public Map<String, Object> getMaxEndTime(OperateBusinessChargeDTO operateBusinessChargeDTO) throws Exception {
        return iOperateBusinessChargeDao.getMaxEndTime(operateBusinessChargeDTO);
    }

    /**
     * <desc>
     *      商务延期处理
     * </desc>
     *
     * @param operateBusinessChargeDTO 商务收费信息DTO
     * @return 标准格式化响应结果
     * @author Juguang.S
     * @createDate 2020/11/26
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void delay(OperateBusinessChargeDTO operateBusinessChargeDTO) throws Exception {

        //更新延期处理数据
        SimpleDateFormat sdf = new SimpleDateFormat(DateUtil.DATE_FORMAT_TYPE1);
        PropertyCloudServiceCostOrderInfoPO propertyCloudServiceCostOrderInfoPO = new PropertyCloudServiceCostOrderInfoPO();
        propertyCloudServiceCostOrderInfoPO.setOrderId(operateBusinessChargeDTO.getOrderId());
        propertyCloudServiceCostOrderInfoPO.setEndTime(sdf.parse(operateBusinessChargeDTO.getDelayEndTime()));
        propertyCloudServiceCostOrderInfoPO.setUpdateTime(new Date());
        propertyCloudServiceCostOrderInfoPO.setDelayRemark(operateBusinessChargeDTO.getDelayRemark());
        propertyCloudServiceCostOrderInfoPO.setDelayMark(1);
        propertyCloudServiceCostOrderInfoPO.setAutoCreatePresent(0);
        iOperateBusinessChargeDao.update(SqlUtil.durableData(propertyCloudServiceCostOrderInfoPO, PlatformConstants.TABLE_UPDATE));

        //项目云服务费变更后需通知该批次号下的云对讲设备
        List<DeviceBusinessChangeLogPO> changeLogPOS = new ArrayList<>();
        JSONArray jsonArray = new JSONArray();
        List<Map<String, String>> deviceList = iWechatPayDao.getDeviceInfoByBatchNumber(operateBusinessChargeDTO.getOrderId());
        if (deviceList != null && !deviceList.isEmpty()) {
            List<Map<String, String>> allDeviceList = iWechatPayDao.getCloudTalkInfoByProjectId(deviceList.get(0).get("projectId"));
            if(allDeviceList != null && !allDeviceList.isEmpty()){
                for (Map<String, String> map : allDeviceList) {
                    if(StringUtils.isEmpty(map.get("deviceUnique"))){
                        continue;
                    }
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("deviceUnique", map.get("deviceUnique"));
                    jsonArray.add(jsonObject);
                }
            }
        }

        //项目云服务费变更后需通知云对讲
        if (!jsonArray.isEmpty()) {
            DeviceBusinessChangeLogPO changeLogPO = new DeviceBusinessChangeLogPO(SmartCommunityEnum.PUSH_DEVICE, jsonArray, deviceList.get(0).get("projectId"));
            changeLogPOS.add(changeLogPO);
        }
        //向设备推送设备云对讲指令
        if (!changeLogPOS.isEmpty()) {
            JSONObject dataJs = new JSONObject();
            dataJs.put("data", changeLogPOS);
            //云对讲
            messageSender.send(RabbitMQConstant.RABBITMQ_HANDLE_SMART_COMMUNITY_ORDERS_QUEUE,
                    JsonUtil.toJSON(dataJs), RabbitMQConstant.RABBITMQ_SMART_COMMUNITY_ORDERS_EXCHANGE,
                    RabbitMQConstant.RABBITMQ_SMART_COMMUNITY_ORDERS_ROUTING_KEY);
        }

        // 保存特殊操作日志
        OperateUserInfoPO operateUserInfoPO = iOperateBusinessChargeDao.getOperateUserPO(operateBusinessChargeDTO.getMyUserName());
        OperationSpecialLogPO operationSpecialLogPO = new OperationSpecialLogPO();
        operationSpecialLogPO.setLogId(LogicIdUtil.bussinessId());
        operationSpecialLogPO.setOuterId(propertyCloudServiceCostOrderInfoPO.getOrderId());
        operationSpecialLogPO.setAccount(operateUserInfoPO.getUserName());
        operationSpecialLogPO.setRealName(operateUserInfoPO.getRealName());
        operationSpecialLogPO.setIp(operateBusinessChargeDTO.getIp());
        operationSpecialLogPO.setFunctionType(1);
        operationSpecialLogPO.setOperateFunction(operateBusinessChargeDTO.getOperateFunction());
        operationSpecialLogPO.setOperateDec(operateUserInfoPO.getRealName() + " 操作延期处理，延期后的时间为：" +  operateBusinessChargeDTO.getDelayEndTime());
        operationSpecialLogPO.setOperateData(JSON.toJSONString(operateBusinessChargeDTO));
        operationSpecialLogPO.setOperateWay(operateBusinessChargeDTO.getOperateWay());
        operationSpecialLogPO.setStatus(DataStatusEnum.NORMAL.getType());
        operationSpecialLogPO.setCreateTime(new Date());
        operationSpecialLogPO.setUpdateTime(new Date());
        iOperateBusinessChargeDao.save(SqlUtil.durableData(operationSpecialLogPO, PlatformConstants.TABLE_SAVE));
    }

    /**
     * <desc>
     *      商务收款确认
     * </desc>
     *
     * @param operateBusinessChargeDTO 商务收费信息DTO
     * @return 标准格式化响应结果
     * @author Juguang.S
     * @createDate 2020/11/26
     */
    public void confirm(OperateBusinessChargeDTO operateBusinessChargeDTO) throws Exception{

        //更新商务收款确认处理数据
        PropertyCloudServiceCostOrderInfoPO propertyCloudServiceCostOrderInfoPO = new PropertyCloudServiceCostOrderInfoPO();
        propertyCloudServiceCostOrderInfoPO.setOrderId(operateBusinessChargeDTO.getOrderId());
        propertyCloudServiceCostOrderInfoPO.setUpdateTime(new Date());
        propertyCloudServiceCostOrderInfoPO.setConfirmRemark(operateBusinessChargeDTO.getRemark());
        propertyCloudServiceCostOrderInfoPO.setCloudServiceAssignment(operateBusinessChargeDTO.getCloudServiceAssignment());
        iOperateBusinessChargeDao.update(SqlUtil.durableData(propertyCloudServiceCostOrderInfoPO, PlatformConstants.TABLE_UPDATE));

        // 保存特殊操作日志
        OperateUserInfoPO operateUserInfoPO = iOperateBusinessChargeDao.getOperateUserPO(operateBusinessChargeDTO.getMyUserName());
        OperationSpecialLogPO operationSpecialLogPO = new OperationSpecialLogPO();
        operationSpecialLogPO.setLogId(LogicIdUtil.bussinessId());
        operationSpecialLogPO.setOuterId(propertyCloudServiceCostOrderInfoPO.getOrderId());
        operationSpecialLogPO.setAccount(operateUserInfoPO.getUserName());
        operationSpecialLogPO.setRealName(operateUserInfoPO.getRealName());
        operationSpecialLogPO.setIp(operateBusinessChargeDTO.getIp());
        operationSpecialLogPO.setFunctionType(1);
        operationSpecialLogPO.setOperateFunction(operateBusinessChargeDTO.getOperateFunction());
        operationSpecialLogPO.setOperateDec(operateUserInfoPO.getRealName() + " 商务收款确认处理，所确认的云服务费任务书号为：" +  operateBusinessChargeDTO.getCloudServiceAssignment());
        operationSpecialLogPO.setOperateData(JSON.toJSONString(operateBusinessChargeDTO));
        operationSpecialLogPO.setOperateWay(operateBusinessChargeDTO.getOperateWay());
        operationSpecialLogPO.setStatus(DataStatusEnum.NORMAL.getType());
        operationSpecialLogPO.setCreateTime(new Date());
        operationSpecialLogPO.setUpdateTime(new Date());
        iOperateBusinessChargeDao.save(SqlUtil.durableData(operationSpecialLogPO, PlatformConstants.TABLE_SAVE));
    }


    /**
     * <desc>
     *      获取项目下可用的批次号列表
     * </desc>
     *
     * @param projectId 项目id
     * @return
     * @Author Zhu.yj
     * @createDate  2021/1/4
     */
    @Override
    public List<String> getProjectBatchNumber(String projectId) throws Exception {
        return iOperateBusinessChargeDao.getBatchNumberByProjectId(projectId);
    }

    /**
     * <desc>
     *      获取审批单表单号
     * </desc>
     *
     * @return 表单单号
     * @Author Zhu.yj
     * @createDate  2021/3/8
     */
    private synchronized String getFormNumber(){
        SimpleDateFormat dateFormat = new SimpleDateFormat("YYMMdd");
        Date now = new Date();
        String dateString = dateFormat.format(now);
        String formNumberString = redisService.get(RedisConstant.OPERATE_BUSINESS_AUDIT_FORM_NUMBER_KEY + dateString);
        if (formNumberString == null){
            String formNumber = dateString + "000001";
            redisService.set(RedisConstant.OPERATE_BUSINESS_AUDIT_FORM_NUMBER_KEY + dateString, RedisConstant.OPERATE_BUSINESS_AUDIT_FORM_NUMBER_TIME, formNumber);
            return formNumber;
        }else {
            long formNumberLong = new Long(formNumberString) + 1;
            redisService.set(RedisConstant.OPERATE_BUSINESS_AUDIT_FORM_NUMBER_KEY + dateString, RedisConstant.OPERATE_BUSINESS_AUDIT_FORM_NUMBER_TIME, Long.toString(formNumberLong));
            return Long.toString(formNumberLong);
        }
    }

}
